package top.cardone.context.func;

import com.google.common.collect.Maps;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import top.cardone.context.ApplicationContextHolder;
import top.cardone.core.CodeException;
import top.cardone.core.util.action.Action3;
import top.cardone.core.util.func.Func2;
import top.cardone.core.util.func.Func3;

import java.util.Map;

/**
 * Created by yao hai tao on 2016/1/18.
 */
@Log4j2
public class FuncAnnotationFunc implements Func2<Object, ProceedingJoinPoint, Map<String, Object>> {
    @Override
    public Object func(ProceedingJoinPoint joinPoint, Map<String, Object> configMap) {
        try {
            final Map<String, Object> contextMap = Maps.newHashMap();

            String[] beforeBeanIds = StringUtils.split(StringUtils.defaultString(MapUtils.getString(configMap, "beforeBeanIds"), MapUtils.getString(configMap, "beforeBeanId")), ",");

            if (ArrayUtils.isNotEmpty(beforeBeanIds)) {
                for (String beforeBeanId : beforeBeanIds) {
                    Object beforeReturnData = ApplicationContextHolder.func(Func3.class, func3 -> func3.func(joinPoint, configMap, contextMap), beforeBeanId);

                    if (beforeReturnData != null) {
                        return beforeReturnData;
                    }
                }
            }

            Object returnData = joinPoint.proceed();

            contextMap.put("returnData", returnData);

            String[] afterBeanIds = StringUtils.split(StringUtils.defaultString(MapUtils.getString(configMap, "afterBeanIds"), MapUtils.getString(configMap, "afterBeanId")), ",");

            if (ArrayUtils.isNotEmpty(afterBeanIds)) {
                for (String afterBeanId : afterBeanIds) {
                    Object afterReturnData = ApplicationContextHolder.func(Func3.class, func3 -> func3.func(joinPoint, configMap, contextMap), afterBeanId);

                    if (afterReturnData != null) {
                        return afterReturnData;
                    }
                }
            }

            return returnData;
        } catch (final Throwable e) {
            String[] errorBeanIds = StringUtils.split(StringUtils.defaultString(MapUtils.getString(configMap, "errorBeanIds"), MapUtils.getString(configMap, "errorBeanId")), ",");

            if (ArrayUtils.isNotEmpty(errorBeanIds)) {
                for (String errorBeanId : errorBeanIds) {
                    ApplicationContextHolder.action(Action3.class, action3 -> {
                        action3.action(joinPoint, configMap, e);
                    }, errorBeanId);
                }
            }

            log.error(e.getMessage(), e);

            throw new CodeException("0000000", e);
        }
    }
}
